#pragma once

#include <string>

#include "Common.h"
#include "FileMgr.h"

/*----------------------------------------------------
 *| 0  |  1  |  2  |  3  |  4 ...-...4+1023 | 1028/9 |
 *+----+-----+-----+-----+------------------+--------+
 *| AA | SEQ | Msg |  R  |    DATA(1024)    |   CRC  |
 *------------------------------------------+--------+*/

#define MSG_HEAD_LEN    4
#define MSG_BODY_LEN    1024
#define MSG_CEC_LEN     2
#define MSG_DATA_LEN    (MSG_HEAD_LEN + MSG_BODY_LEN)
#define MSG_TOTAL_LEN   (MSG_DATA_LEN + MSG_CEC_LEN)

typedef enum
{
    MSG_ACK   = 1,
    MSG_NACK   = 2,
    MSG_HELLO = 3,
    MSG_COMPLETE,

    MSG_FDISK = 8,
    MSG_MKFS,
    MSG_CREATE_FOLDER ,
    MSG_CREATE_FILE,
    MSG_GET_FILE_INFO,
    MSG_OPEN_FILE,
    MSG_CLOSE_FILE,
    MSG_WRITE_BLOCK,
    MSG_WRITE_REMNANT,
    MSG_FILE_INFO,
    MSG_DELETE,
}PktMsg_E;

typedef enum
{
    ST_IDLE,
    ST_SETUP,
    ST_FDISK,
    ST_MKFS,
    ST_OPEN,
    ST_COMPLETE,
    ST_TRANSMIT, //transmit
    ST_FAILED,
    ST_DELETE,

    ST_WAIT = 0x40,
}PktState_E;

typedef enum
{
    OPT_NORMAL,
    OPT_MKFS,
    OPT_DELETE,
};

typedef struct
{
    uint8_t   magic;
    uint8_t   seqnum;
    uint8_t   msgid;
    uint8_t   resv;
    uint8_t   body[MSG_BODY_LEN];
    uint16_t  crc16;
}PktMsg_T;

typedef struct
{
    uint8_t     seqnum;
    uint8_t     recv;
    uint16_t    ackcode;
}PktComAck_T;

typedef struct
{
    uint8_t     seqnum;
    uint8_t     resv;
    uint16_t    ackcode;

    uint8_t     state;
    uint8_t     resv2;
    uint16_t    fcrc16;
    uint32_t    fsize;
}PktFileInfo_T;

typedef struct
{
    uint8_t     seqnum;
    uint8_t     resv;
    uint16_t    ackcode;

    uint32_t    total;
    uint32_t    free;
}PktDiskInfo_T;

class Packet
{
public:
    Packet(int step, const char* path = "");
    Packet(const char* path, const char* name, int type = FTYPE_FILE);
    virtual ~Packet();

    PktState_E GetState() { return m_nState; };
    void SetState(PktState_E iState);
    int Process();
    void bind(LinkHand link) { m_hLink = link; };
    int    TestProc();

private:
    uint8_t GetSeqNum();
    int     GetResponse() { return 1; };
    int     SendMsg(PktMsg_T& msg, int retry = 0);
    int     RecvMsg();
    int     RecvMsgHandler(PktMsg_T& msg);

private:
    int         m_nType;
    char        m_strPath[128];
    LinkHand    m_hLink;
    PktMsg_T    m_tMsgRT;
    uint64_t    m_uLastTime;
    uint32_t    m_uReTry;
    bool        m_bWaitFlag;
    uint8_t*    m_ReadBuf;

    char        m_strFileName[128];
    uint32_t    m_nFileSize;
    uint16_t    m_uFileCRC;
    FILE*       m_hFile;

    uint16_t    m_uTargetCRC;
    uint32_t    m_uTargetSize;

    PktState_E  m_nState;
    PktState_E  m_nNextState;
};

class MCUDev
{
public:
    MCUDev(const char* root);
    ~MCUDev();

public:
    PktMsg_E GetState();

    void Process();
    void bind(LinkHand link) { m_hLink = link; };

private:
    uint8_t GetSeqNum();
    int     SendMsg(PktMsg_T& msg);
    int     RecvMsg(PktMsg_T& msg);

private:
    char            m_strRoot[128];
    LinkHand        m_hLink;
    FILE*           m_hFile;
    uint8_t         m_uSeqNum;
    uint16_t        m_uLatWrSeq;
    int             m_nType;

    uint8_t*        m_ReadBuf;
};